package com.sharemarking.wa.platform.service;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.sharemarking.wa.common.ResponseParams;
import com.sharemarking.wa.common.entity.*;
import com.sharemarking.wa.common.eum.OrderStateEum;
import com.sharemarking.wa.common.exception.RequestException;
import com.sharemarking.wa.platform.dto.ConfigInfo;
import com.sharemarking.wa.platform.mapper.*;
import com.sharemarking.wa.platform.payconfig.OrderQueryService;
import com.sharemarking.wa.platform.payconfig.wx.MyWXConfig;
import com.sharemarking.wa.platform.payconfig.wx.WXPay;
import com.sharemarking.wa.platform.payconfig.wx.WXPayUtil;
import com.sharemarking.wa.platform.payconfig.zfb.ZFBPayMain;
import com.sharemarking.wa.platform.service.OrderDelayQueue.OrderDelay;
import com.sharemarking.wa.platform.service.OrderDelayQueue.OrderQueue;
import com.sharemarking.wa.platform.service.impl.Md5ServiceImpl;
import com.sharemarking.wa.platform.utils.IpUtils;

import org.apache.http.HttpResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.tio.websocket.common.util.Md5;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author dxy
 */
@Service
public class OrderPayService {
    @Value("${ali.pay.alipayPublicCertPath}")
    private String publicKeyCertPath;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private SecurityService ss;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private PayRecordMapper payRecordMapper;
    @Autowired
    private OrderPayMapper payMapper;
    @Autowired
    private OrgMemberMapper orgMemberMapper;
    @Autowired
    private InvoiceMapper invoiceMapper;
    @Autowired
    private OrgMapper orgMapper;
    @Autowired
    private MemberMapper memberMapper;
    @Autowired
    private MyWXConfig config;
    @Autowired
    private ZFBPayMain zfbPayMain;
    @Autowired
    private HttpServletResponse response;
    @Autowired
    private OrderQueryService queryService;
    @Autowired
    private OrderQueue orderQueue;
    @Autowired
    private Md5ServiceImpl md5Service;
    @Autowired
    private JGPushService jgPushService;
    @Autowired
    private DictMapper dictMapper;
    public ResponseParams<?> getFees() throws Exception {
        Integer memberId = ss.getCurrentUserId();
        String code = request.getParameter("code");

        if (StringUtils.isEmpty(code)) {
            throw RequestException.create(ResponseParams.requiredParamsIsMissing("code"));
        }


        Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("code", code));


        //验证订单权限
//        if (!order.getReceiveOrgMemberId().equals(memberId) || !order.getType().equals(1) || !order.getSendOrgMemberId().equals(memberId)) {
//            throw RequestException.create(ResponseParams.error(REQUIRED_PARAMS_IS_MISSING));
//        }

        Map<String, Object> params = new HashMap<>();
        params.put("fess", order.getTransportFees() * 0.01);

        return ResponseParams.ok(params);
    }

    @Transactional(rollbackFor = Exception.class)
    public ResponseParams<?> wxPay() throws Exception {
        Integer memberId = ss.getCurrentUserId();

        String code = request.getParameter("code");

        if (StringUtils.isEmpty(code)) {
            throw RequestException.create(ResponseParams.requiredParamsIsMissing("code"));
        }
        if (queryService.query(code)) {
            throw RequestException.create(ResponseParams.isDataError("该订单已被支付"));
        }
        Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("code", code));
        if (order == null) {
            throw RequestException.create(ResponseParams.isDataError("订单不存在"));
        }
        //移除队列中将要过期的元素
        orderQueue.getQueue().remove(new OrderDelay(order.getId()));

        WXPay wxpay = new WXPay(config);

        Map<String, String> data = new HashMap<String, String>();
        data.put("body", "运费支付");
        data.put("detail", "运费支付");
        data.put("out_trade_no", order.getCode());
        data.put("fee_type", "CNY");
        data.put("total_fee", String.valueOf(order.getTransportFees()));
        data.put("spbill_create_ip", IpUtils.getIpAddress(request));
        data.put("notify_url", config.getNotifyUrl());
        data.put("trade_type", "APP");  // 交易类别
        data.put("attach", String.valueOf(memberId));//传用户id

        Map<String, String> resp = wxpay.unifiedOrder(data);
        if (resp.get("result_code").equals("FAIL")) {
            return ResponseParams.ok(resp.get("err_code_des"));
        }
        return ResponseParams.ok(wxpay.appResultMap(resp));
    }

    @Transactional(rollbackFor = Exception.class)
    public ResponseParams<?> alPay() throws Exception {
        Integer memberId = ss.getCurrentUserId();
        String code = request.getParameter("code");


        if (StringUtils.isEmpty(code)) {
            throw RequestException.create(ResponseParams.requiredParamsIsMissing("code"));
        }
        if (queryService.query(code)) {
            throw RequestException.create(ResponseParams.isDataError("该订单已被支付"));
        }
        Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("code", code));
        if (order == null) {
            throw RequestException.create(ResponseParams.isDataError("订单不存在"));
        }
        //移除队列中将要过期的元素
        orderQueue.getQueue().remove(new OrderDelay(order.getId()));

        Map<String, String> map = new HashMap<>();
        map.put("code", code);
        map.put("body", "运费支付");
        map.put("subject", "运费支付");
        //特别注意支付宝金额格式，单位为元，精确到小数点后两位，取值范围[0.01,100000000]
        map.put("transportFees", String.format("%.2f", order.getTransportFees() * 0.01));
        map.put("passback_params", String.valueOf(memberId));
        return ResponseParams.ok(zfbPayMain.AppPay(map));
    }

    @Transactional(rollbackFor = Exception.class)
    public ResponseParams<?> publisherPay() throws Exception {
        Integer memberId = ss.getCurrentUserId();
        String code = request.getParameter("code");
        if (StringUtils.isEmpty(code)) {
            throw RequestException.create(ResponseParams.requiredParamsIsMissing("code"));
        }

        Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("code", code).eq("receive_org_member_id", memberId));

        if (order == null || (order.getPayer() != null && order.getPayer() == 0) || !order.getState().equals(OrderStateEum.UNPAID.getKey())) {
            throw RequestException.create(ResponseParams.isDataError("无效操作"));
        }

        Order o = new Order();
        o.setPayer(1);
        o.setUpdateDate(new Date());
        o.setCode(code);

        payMapper.publisherPay(o);

        String messageStr = "您好，尾号为"+order.getCode().substring(order.getCode().length() - 10)+"的子订单需要您支付运输费用,请在10分钟内进行支付，否则该订单将自动取消";
        jgPushService.pushTag(messageStr,order.getSendOrgMemberId());

        return ResponseParams.ok(null);
    }

    //是否有月结支付密码
    public ResponseParams<?> isMonthPayPassword() throws Exception{
        Integer memberId = ss.getCurrentUserId();
        Map<String, Integer> resultMap = new HashMap<>();
        if (memberMapper.get(memberId).getPayPassword()==null) {
            resultMap.put("message",0);
        }else{
            resultMap.put("message",1);
        }
        return ResponseParams.ok(resultMap);
    }

    @Transactional(rollbackFor = Exception.class)
    public ResponseParams<?> monthPay() throws Exception {
        Integer memberId = ss.getCurrentUserId();
        String code = request.getParameter("code");
        String payPassword = request.getParameter("payPassword");

        if (StringUtils.isEmpty(code)) {
            throw RequestException.create(ResponseParams.requiredParamsIsMissing("code"));
        }
        if (StringUtils.isEmpty(payPassword)) {
            throw RequestException.create(ResponseParams.requiredParamsIsMissing("payPassword"));
        }

        if (!memberMapper.get(memberId).getPayPassword().equals(md5Service.md5(payPassword))) {
            throw RequestException.create(ResponseParams.isDataError("支付密码错误"));
        }

        Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("code", code).eq("receive_org_member_id", memberId));
        if (order == null) {
            throw RequestException.create(ResponseParams.isDataError("订单不存在"));
        }
        if (order == null || !order.getState().equals(4)) {
            throw RequestException.create(ResponseParams.isDataError("无效操作"));
        }

        //移除队列中将要过期的元素
        orderQueue.getQueue().remove(new OrderDelay(order.getId()));

        Invoice invoice = new Invoice();
        invoice.setType(1);
        invoice.setMemberId(memberId);
        invoice.setOrgId(orgMemberMapper.selectOne(new QueryWrapper<OrgMember>().eq("member_id", memberId)).getOrgId());
        invoice.setTransactionType(0);
        invoice.setDescription(code + "订单运输费用");
        invoice.setTransactionCode(code);
        invoice.setInvoiceCode("month" + createNumber(null));
        invoice.setState(2);
        invoice.setPayDate(new Date());
        invoice.setCreateDate(new Date());
        invoice.setAmount(order.getTransportFees());
        invoiceMapper.insert(invoice);

        int state;
        if (order.getDriverId() == null) {
            state = OrderStateEum.TRANSPORT_RECEIPT.getKey();//待运输单位接单
        } else {
            state = OrderStateEum.DRIVER_CONFIRM.getKey();//待司机确认
        }
        Order payOrder = new Order();
        payOrder.setCode(code);
        payOrder.setState(state);
        payOrder.setUpdateDate(new Date());
        if (order.getPayer() == null && order.getReceiveOrgMemberId().equals(memberId)) {
            //接单的和现在支付的memberId一样，为经营方支付
            payOrder.setPayer(0);
            payMapper.updateOrderStateAndPayer(payOrder);
        } else {
            payMapper.updateOrderState(payOrder);
        }

        PayRecord payRecord = new PayRecord();
        payRecord.setAmount(order.getTransportFees());
        payRecord.setTransactionType(0);
        payRecord.setMemberId(memberId);
        payRecord.setPayTime(new Date());
        payRecord.setPayWay(2);
        payRecord.setTransactionCode(order.getCode());
        payRecord.setPayCode("month" + createNumber(null));
        payRecord.setIsReceipt(0);
        payRecord.setCreateDate(new Date());
        payRecord.setDescription(code + "订单运输费用");
        payRecordMapper.insert(payRecord);


        return ResponseParams.ok(null);
    }


    public static String createNumber(String code) {
        StringBuilder newCode = new StringBuilder();
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmm"); // 时间字符串产生方式
        String timeCode = format.format(new Date()); // 组合流水号前一部分，时间字符串，如：202002111200
        if (code != null && code.substring(0, 12).equals(timeCode.substring(0, 12))) {
            Integer codeEnd = Integer.valueOf("1" + code.substring(12, 16)) + 1;//单号+1
            timeCode = timeCode + String.valueOf(codeEnd).substring(1, 5);
        } else {
            timeCode = timeCode + "0001";
        }
        newCode.append(timeCode);

        return newCode.toString();

    }


    public ResponseParams<?> isMonthPay() throws Exception {
        Integer memberId = ss.getCurrentUserId();
        Integer isOrgMonthPay = orgMapper.isOrgMonthPay(memberId);

        Map<String, Object> map = new HashMap<>();

        if (isOrgMonthPay == null || isOrgMonthPay == 0) {
            map.put("monthPay", 0);
        }else {
            map.put("monthPay", 1);
        }


        if (isOrgMonthPay != null && isOrgMonthPay == 1) {
            //是否是第一次使用
            int isFirst;
            String pwd = memberMapper.getPayPwdByMemberId(memberId);
            if (StringUtils.isEmpty(pwd)) {
                isFirst = 1;
            } else {
                isFirst = 0;
            }
            map.put("isFirst", isFirst);
        }
        if (memberMapper.get(memberId).getPayPassword()==null) {
            map.put("monthPassword",0);
        }else{
            map.put("monthPassword",1);
        }
        ConfigInfo configInfo=dictMapper.getConfigInfo();
        map.put("mobile",configInfo.getServiceMobile());
        return ResponseParams.ok(map);
    }


    public String wxNotify() throws Exception {
        //获取回调xml
        String inputLine;
        String notifyXml = "";
        try {
            while ((inputLine = request.getReader().readLine()) != null) {
                notifyXml += inputLine;
            }
            request.getReader().close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        WXPay wxpay = new WXPay(config);
        Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyXml);  // 转换成map

        if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
            // 签名正确
            // 进行处理。
            // 注意特殊情况：订单已经退款，但收到了支付结果成功的通知，不应把商户侧订单状态从退款改成支付成功

            //业务订单号
            String code = notifyMap.get("out_trade_no");

            Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("code", code));

            Integer memberId = Integer.valueOf(notifyMap.get("attach"));
            PayRecord payRecord = new PayRecord();
            payRecord.setAmount(order.getTransportFees());
            payRecord.setPayCode(code);
            payRecord.setDescription(code + "订单运输费用");
            payRecord.setIsReceipt(0);
            payRecord.setPayTime(new Date());
            payRecord.setMemberId(memberId);
            payRecord.setTransactionType(0);
            //微信支付订单号
            payRecord.setPayCode(notifyMap.get("transaction_id"));
            payRecord.setTransactionCode(code);//获取微信支付订单号
            payRecord.setCreateDate(new Date());
            payRecord.setPayWay(0);//微信支付
            payRecordMapper.insert(payRecord);

            //设置订单状态
            int state = 0;
            if (order.getDriverId() == null) {
                state = OrderStateEum.TRANSPORT_RECEIPT.getKey();//待运输单位接单
            } else {
                state = OrderStateEum.DRIVER_CONFIRM.getKey();//待司机确认
            }
            Order newOrder = new Order();
            newOrder.setCode(code);
            newOrder.setState(state);
            newOrder.setUpdateDate(new Date());

            if (order.getPayer() == null && order.getReceiveOrgMemberId().equals(memberId)) {
                //接单的和现在支付的memberId一样，为经营方支付
                newOrder.setPayer(0);
                payMapper.updateOrderStateAndPayer(newOrder);
            } else {
                payMapper.updateOrderState(newOrder);
            }
        }


        //生成返回成功接收的xml字符串
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("return_code", "SUCCESS");
        resultMap.put("return_msg", "OK");
        WXPayUtil.mapToXml(resultMap);
        return WXPayUtil.mapToXml(resultMap);
    }


    public String zfbNotify() throws Exception {

        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
//            System.out.println("name:"+name+" valueStr:"+valueStr);
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        boolean flag = AlipaySignature.rsaCertCheckV1(params, publicKeyCertPath, "UTF-8", "RSA2");

        if (flag) {
            //验证订单号是否正确
            Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("code", params.get("out_trade_no")));
//            //验证金额是否正确
//            params.get("total_amount");
//            //验证seller_id是否正确
//            params.get("seller_id");
//            //验证appId是否正确
//            params.get("app_id");

            if (params.get("total_amount").equals(String.format("%.2f", order.getTransportFees() * 0.01)) &&
                    params.get("app_id").equals("2021001168651345") &&
                    params.get("trade_status").equals("TRADE_SUCCESS")) {

                //获取从支付宝传递的memberId
                Integer memberId = Integer.valueOf(params.get("passback_params"));

                PayRecord payRecord = new PayRecord();
                payRecord.setAmount(order.getTransportFees());
                payRecord.setTransactionCode(order.getCode());
                payRecord.setIsReceipt(0);
                payRecord.setDescription(params.get("trade_no") + "订单运输费用");
                payRecord.setPayTime(new Date());
                payRecord.setMemberId(memberId);
                payRecord.setTransactionType(0);
                payRecord.setPayCode(params.get("trade_no"));//支付宝支付订单号
                payRecord.setCreateDate(new Date());
                payRecord.setPayWay(1);//支付宝支付

                payRecordMapper.insert(payRecord);

                //设置订单状态
                int state = 0;

                if (order.getDriverId() == null) {
                    state = OrderStateEum.TRANSPORT_RECEIPT.getKey();//待运输单位接单
                } else {
                    state = OrderStateEum.DRIVER_CONFIRM.getKey();//待司机确认
                }
                Order o = new Order();
                o.setCode(order.getCode());
                o.setState(state);
                o.setUpdateDate(new Date());
                if (order.getPayer() == null && order.getReceiveOrgMemberId().equals(memberId)) {
                    //接单的和现在支付的memberId一样，为经营方支付
                    o.setPayer(0);
                    payMapper.updateOrderStateAndPayer(o);
                } else {
                    payMapper.updateOrderState(o);
                }
            }
        }

        return "success";
    }

    public ResponseParams<?> getWxPayCode() throws Exception {
        Integer memberId = ss.getCurrentUserId();
        String code = request.getParameter("code");
        if (queryService.query(code)) {
            throw RequestException.create(ResponseParams.isDataError("该订单已被支付"));
        }
        if (StringUtils.isEmpty(code)) {
            throw RequestException.create(ResponseParams.requiredParamsIsMissing("code"));
        }

        String tradeType = "NATIVE";

        Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("code", code));

        //移除队列中将要过期的元素
        orderQueue.getQueue().remove(new OrderDelay(order.getId()));

        WXPay wxpay = new WXPay(config);

        Map<String, String> data = new HashMap<String, String>();
        data.put("body", "运费支付");
        data.put("detail", "运费支付");
        data.put("out_trade_no", order.getCode());
        data.put("fee_type", "CNY");
        data.put("total_fee", String.valueOf(order.getTransportFees()));
        data.put("spbill_create_ip", IpUtils.getIpAddress(request));
        data.put("notify_url", config.getNotifyUrl());
        data.put("trade_type", tradeType);  // 交易类别
        data.put("attach", String.valueOf(memberId));//传用户id

        Map<String, String> resp = wxpay.unifiedOrder(data);
        if (resp.get("result_code").equals("SUCCESS")) {
            String info = resp.get("code_url");
            return ResponseParams.ok(getPayCodeImage(info));
        }
        return ResponseParams.ok(null);
    }


    public void getAlPayCode() throws Exception {
        Integer memberId = ss.getCurrentUserId();
        String code = request.getParameter("code");

        if (queryService.query(code)) {
            throw RequestException.create(ResponseParams.isDataError("该订单已被支付"));
        }

        if (StringUtils.isEmpty(code)) {
            throw RequestException.create(ResponseParams.requiredParamsIsMissing("code"));
        }

        Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("code", code));
        //移除队列中将要过期的元素
        orderQueue.getQueue().remove(new OrderDelay(order.getId()));

        Map<String, String> map = new HashMap<>();
        map.put("out_trade_no", code);
        map.put("body", "运费支付");
        map.put("subject", "运费支付");
        //特别注意支付宝金额格式，单位为元，精确到小数点后两位，取值范围[0.01,100000000]
        map.put("total_amount", String.format("%.2f", order.getTransportFees() * 0.01));
        map.put("passback_params", String.valueOf(memberId));
        map.put("product_code", "FAST_INSTANT_TRADE_PAY");

        String result = zfbPayMain.PCPay(map);
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write(result);
        response.getWriter().flush();
        response.getWriter().close();
    }


    public ResponseParams<?> isPay() throws Exception {
        Integer memberId = ss.getCurrentUserId();
        String code = request.getParameter("code");


        if (StringUtils.isEmpty(code)) {
            throw RequestException.create(ResponseParams.requiredParamsIsMissing("code"));
        }

        Integer count = payRecordMapper.selectCount(new QueryWrapper<PayRecord>().eq("transaction_code", code));
        if (count == 0) {
            return ResponseParams.ok(false);
        } else if (count == 1) {
            return ResponseParams.ok(true);
        } else {
            throw RequestException.create(ResponseParams.isDataError("支付错误，请马上联系网站管理员"));
        }

    }


    /***************生成二维码方法**********************/

    public String getPayCodeImage(String info) {
        byte[] qrcode = null;
        try {
            qrcode = getQRCodeImage(info, 360, 360);
        } catch (WriterException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "data:image/png;base64," + Base64.getEncoder().encodeToString(qrcode);
    }

    public static byte[] getQRCodeImage(String text, int width, int height) throws WriterException, IOException {
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
        ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();
        MatrixToImageWriter.writeToStream(bitMatrix, "PNG", pngOutputStream);
        byte[] pngData = pngOutputStream.toByteArray();
        return pngData;
    }
}
